import time
import requests
from parsel import Selector
from django.core.management import BaseCommand
from django.utils import timezone
from django.db import transaction
from django.db.models import Q
from django.db.models.functions import Cast
from django.db.models import IntegerField
from crawler.models import LotteryData


class Command(BaseCommand):
    help = '彩票数据抓取（精确生成未来1期，保留50期历史）'

    def add_arguments(self, parser):
        parser.add_argument(
            '--url',
            type=str,
            default="https://www.zzwbgg.com",
            help='目标网站URL（默认：https://www.zzwbgg.com）'
        )
        parser.add_argument(
            '--interval',
            type=int,
            default=3,
            help='抓取间隔（秒），默认3秒'
        )

    def handle(self, *args, ** options):
        interval = options['interval']
        self.stdout.write(self.style.SUCCESS(f"[{timezone.now()}] 启动定时抓取，间隔 {interval} 秒"))

        try:
            while True:
                try:
                    with transaction.atomic():
                        self.stdout.write(f"\n[{timezone.now()}] 开始新一轮抓取...")
                        data = self.fetch_all_data(options['url'])

                        # 处理历史数据
                        if data.get("history"):
                            self.process_history(data["history"])

                        # 处理实时数据
                        if data.get('realtime'):
                            current_issue = self.process_realtime(data['realtime'])
                            if current_issue:
                                self.generate_next_issue(current_issue)

                        # 清理旧数据
                        self.clean_old_data()

                        self.stdout.write(self.style.SUCCESS(f"[{timezone.now()}] 本轮抓取完成"))

                except Exception as e:
                    self.stderr.write(self.style.ERROR(f"本轮抓取出错: {str(e)}"))

                time.sleep(interval)

        except KeyboardInterrupt:
            self.stdout.write(self.style.WARNING("\n用户手动终止抓取"))

    def fetch_all_data(self, url):
        """保持原有解析逻辑不变"""
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
            "Referer": url
        }

        try:
            response = requests.get(url, headers=headers, timeout=15)
            response.raise_for_status()
            sel = Selector(text=response.text)

            sum_value = sel.css(".newissue-box-result > span::text").get()
            codes_part = "".join(
                sel.css(".newissue-box-result-item span::text, .newissue-box-result-item i::text").getall()
            )
            realtime_data = {
                "当前期号": sel.css(".newissue-box-num span::text").get(),
                "开奖号码": codes_part + sum_value if codes_part else "",
                "总和": sum_value
            }

            history_data = []
            for item in sel.css('div.tabbar-history-item-content-item'):
                history_data.append({
                    "期号": item.xpath('.//span[1]/text()').get(),
                    "时间": item.xpath('.//span[2]/text()').get(),
                    "号码": item.xpath('.//span[3]/text()').get()
                })

            return {
                "realtime": realtime_data,
                "history": history_data
            }

        except requests.exceptions.RequestException as e:
            raise Exception(f"网络请求失败: {str(e)}")
        except Exception as e:
            raise Exception(f"解析失败: {str(e)}")

    def process_realtime(self, data):
        """处理实时数据（使用status字段）"""
        try:
            current_issue = data["当前期号"]
            issue_int = int(current_issue)
            sum_value = int(data["总和"]) if data["总和"].isdigit() else -1
        except (ValueError, TypeError):
            self.stdout.write(f"无效的实时数据: {data}")
            return None

        obj, created = LotteryData.objects.update_or_create(
            issue_number=current_issue,
            defaults={
                'numbers': data["开奖号码"],
                'sum_value': sum_value,
                'status': 'closed' if sum_value != -1 else 'pending',
                'start_time': timezone.now()
            }
        )

        self.stdout.write(f"实时数据更新：{current_issue}（{'新建' if created else '更新'}）")
        return issue_int

    def generate_next_issue(self, current_issue):
        """生成下一期预测数据（使用status字段）"""
        next_issue = current_issue + 1
        if not LotteryData.objects.filter(issue_number=next_issue).exists():
            LotteryData.objects.create(
                issue_number=next_issue,
                numbers="等待开奖",
                sum_value=-1,
                status='pending',
                start_time=timezone.now()
            )
            self.stdout.write(f"生成预测期号：{next_issue}")

    def process_history(self, history_list):
        """处理历史数据（使用status字段）"""
        new_count = 0
        for item in history_list:
            try:
                issue = int(item["期号"])
                numbers = item["号码"]
                if "=" not in numbers:
                    continue
            except (ValueError, KeyError):
                continue

            obj, created = LotteryData.objects.get_or_create(
                issue_number=issue,
                defaults={
                    'numbers': numbers,
                    'sum_value': self.parse_sum(numbers),
                    'status': 'closed',
                    'start_time': timezone.now()
                }
            )
            if created:
                new_count += 1
                self.stdout.write(f"新增历史期号：{issue}")

        self.stdout.write(f"共处理历史数据{len(history_list)}条，新增{new_count}条")

    def parse_sum(self, numbers):
        """从号码字符串解析总和"""
        try:
            return int(numbers.split("=")[-1].strip())
        except:
            return -1

    def clean_old_data(self):
        """更新后的清理逻辑（使用status字段）"""
        with transaction.atomic():
            # 保留所有未开奖数据
            pending_issues = LotteryData.objects.filter(status='pending').values_list('issue_number', flat=True)

            # 获取最新的50期已开奖数据
            keep_historical = LotteryData.objects.filter(status='closed').annotate(
                issue_int=Cast('issue_number', IntegerField())
            ).order_by('-issue_int').values_list('issue_number', flat=True)[:50]

            # 合并需要保留的期号
            keep_ids = list(pending_issues) + list(keep_historical)

            # 执行删除操作
            deleted_count, _ = LotteryData.objects.exclude(
                Q(issue_number__in=keep_ids)
            ).delete()

            if deleted_count > 0:
                self.stdout.write(f"清理过期数据：{deleted_count}条（保留未开奖{len(pending_issues)}期+最新50期已开奖）")